package com.example.budget3.months;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.budget3.R;
import com.example.budget3.months.graphs.Bar;
import com.example.budget3.months.graphs.BarGraph;
import com.example.budget3.months.graphs.DonutGraph;
import com.example.budget3.months.graphs.DonutSlice;
import com.example.budget3.months.graphs.Line;
import com.example.budget3.months.graphs.LineGraph;
import com.example.budget3.months.graphs.LinePoint;
import com.example.budget3.data.ExpenseCategory;
import com.example.budget3.data.TransactionData;
import com.example.budget3.modify.EditTransaction;
import com.example.budget3.settings.UserSettingActivity;
import com.example.budget3.util.DatabaseQueryHandler;
import com.example.budget3.util.UtilMethods;
import com.haarman.listviewanimations.swinginadapters.AnimationAdapter;
import com.haarman.listviewanimations.swinginadapters.prepared.SwingBottomInAnimationAdapter;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import com.tjerkw.slideexpandable.library.ActionSlideExpandableListView;

public class ListFragment extends Fragment {
	
	public interface OnPageChangeListener {
		
		public void pageChange();

		public void onPageScrollStateChanged(int state);

		public void onPageScrolled(int position, float positionOffset,
				int positionOffsetPixels);

		public void onPageSelected(int position);

	}

	private static final String HEADER_PAGE = "header";
	private int month;

	private ActionSlideExpandableListView list;
	private View listContainer;
	private int headerPage;
	private MainActivity context;
	private List<TransactionData> data;
	private TransactionListAdapter transactionListAdapter;
	private Calendar latest;
	private View header;
	private String budget;
	private LayoutInflater inflater;
	private ListFragment thisFragment;
	private LinearLayout pie;
	private LinearLayout line;
	private LinearLayout bar;
	private DotsPageIndicator headerIndicator;
	
	private class FlipOnClick  implements OnClickListener{

		@Override
		public void onClick(View v) {
			headerIndicator.onPageSelected((headerPage+1)%getHeaderCount());
			flipHeaders((headerPage+1)%getHeaderCount());
		}
	}
	
	@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			
	    this.inflater = inflater;
	    this.thisFragment = this;
	    this.context = (MainActivity) getActivity();
	    
	    if(savedInstanceState != null){
	    	headerPage = savedInstanceState.getInt(HEADER_PAGE);
	    }else{
	    	headerPage = 0;
	    }
	    
	    Bundle args = getArguments();
		month = args.getInt(MonthPagerAdapter.ARG_MONTH_NUMBER);
		latest = Calendar.getInstance();
		latest.setTimeInMillis(args.getLong(MonthPagerAdapter.ARG_LATEST));
		listContainer = inflater.inflate(R.layout.month_transaction_list, container, false);
		list = (ActionSlideExpandableListView) listContainer.findViewById(R.id.transactions_list);

		checkForChanges();
		
		list.setItemActionListener(new ActionSlideExpandableListView.OnActionClickListener() {

             @Override
             public void onClick(View listView, View buttonview, final int position) {
                 if(buttonview.getId()==R.id.deleteBtn) {
            	 	DialogFragment newFragment = new DeleteDialogFragment();
            	 	Bundle positionBundle = new Bundle();
            	 	positionBundle.putInt(DeleteDialogFragment.POSITION_ARG, position);
					newFragment.setArguments(positionBundle);
					newFragment.setTargetFragment(thisFragment, 1);
 		        	newFragment.show(getFragmentManager(), null); 
     			 }else{
     				Bundle bundle = new Bundle();
     				TransactionData entry = data.get(position);
     				bundle.putInt(EditTransaction.ENTRY_ID, entry.getID());
     				Intent editIntent = new Intent(context, EditTransaction.class);
     				editIntent.putExtras(bundle);
     				context.startActivityForResult(editIntent, MainActivity.RESULT_EDIT);	
     			 }
             }
		}, R.id.editBtn, R.id.deleteBtn);
		
		list.setClipToPadding(false);
		// Sets the padding to the insets (include action bar and navigation bar padding for the current device and orientation)
		setInsets(getActivity(),list);
		
		return listContainer;
	}

	public void checkForChanges() {
		context = (MainActivity) getActivity();
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
		budget = preferences.getString(UserSettingActivity.KEY_BUDGET_PREFERENCE, "1000");
		loadData();
		list.removeHeaderView(header);
		header = addHeader();
		list.addHeaderView(header);
		transactionListAdapter = new TransactionListAdapter(context, R.layout.transactionslist_rowlayout, data);
		AnimationAdapter animAdapter = new SwingBottomInAnimationAdapter(transactionListAdapter);
		animAdapter.setAbsListView(list);
		list.setAdapter(animAdapter);
		transactionListAdapter.notifyDataSetChanged();
		list.collapse();
	}
	
	public void removeItem(int position) {
		list.collapse();
		TransactionData item = data.get(position);
		DatabaseQueryHandler.removeTransaction(context, item);
		data.remove(position);
		transactionListAdapter.notifyDataSetChanged();
		Toast.makeText(context, "Removed: " + item.getName(), Toast.LENGTH_SHORT).show();
		if(data.isEmpty()){
			((MainActivity) context).checkForChanges(true);
		}

	}
		
	@Override
	public void onSaveInstanceState(Bundle outState) {
		outState.putInt(HEADER_PAGE, headerPage);
		super.onSaveInstanceState(outState);
	}
	
	private void loadData() {
		List<TransactionData> localData = DatabaseQueryHandler.getAllTransactions(context,latest,month);
		if(data == null){
			data = localData;
		}else if(!data.equals(localData)){
			data.clear();
			data.addAll(localData);
		}
	}
	
	private View addHeader() {
		
		View header = inflater.inflate(R.layout.month_transaction_header, null, false); 
		View container = header.findViewById(R.id.headerContainer); 
		headerIndicator = (DotsPageIndicator) header.findViewById(R.id.indicator);
		headerIndicator.setViewPager(this);
		headerIndicator.setCurrentItem(headerPage);
		pie =  (LinearLayout) header.findViewById(R.id.pie);
		line =  (LinearLayout) header.findViewById(R.id.line);
		bar =  (LinearLayout) header.findViewById(R.id.bar);
		if(headerPage ==0){
			pie.setVisibility(View.VISIBLE);
			line.setVisibility(View.INVISIBLE);
			bar.setVisibility(View.INVISIBLE);
		}else if (headerPage == 1) {
			pie.setVisibility(View.INVISIBLE);
			line.setVisibility(View.VISIBLE);
			bar.setVisibility(View.INVISIBLE);
		}else if (headerPage == 2) {
			line.setVisibility(View.INVISIBLE);
			pie.setVisibility(View.INVISIBLE);
			bar.setVisibility(View.VISIBLE);
		}
		
		drawPieGraph(header);
		drawLineGraph(header);
		drawBarGraph(header); 
		container.setOnClickListener(new FlipOnClick()); 
		return header;
		
	}
	
	private void flipHeaders(int page){
		 Animation out = AnimationUtils.makeOutAnimation(context, true);
		 Animation in = AnimationUtils.makeInAnimation(context, true);
		 headerPage = page;
		 if(page == 0){
			 bar.startAnimation(out);
			 bar.setVisibility(View.INVISIBLE);
			 pie.startAnimation(in);
			 pie.setVisibility(View.VISIBLE);  
		 }else if(page == 1){
			 pie.startAnimation(out);
			 pie.setVisibility(View.INVISIBLE);
			 line.startAnimation(in);
			 line.setVisibility(View.VISIBLE);
		 }else if(page == 2){
			 line.startAnimation(out);
			 line.setVisibility(View.INVISIBLE);
			 bar.startAnimation(in);
			 bar.setVisibility(View.VISIBLE);
		 }
	}

	private void drawPieGraph(View header) {
		
		DonutGraph donutGraph = (DonutGraph) header.findViewById(R.id.donut_graph);
		TextView budgetText = (TextView) header.findViewById(R.id.textBudgetValue);
		TextView totalText = (TextView) header.findViewById(R.id.textTotalValue);
		
		TextView foodText= (TextView) header.findViewById(R.id.food_title);
		TextView billsText = (TextView) header.findViewById(R.id.bills_title);
		TextView leisureText = (TextView) header.findViewById(R.id.leisure_title);
		TextView travelText = (TextView) header.findViewById(R.id.travel_title);
		TextView utilitiesText= (TextView) header.findViewById(R.id.utilities_title);
		TextView rentText = (TextView) header.findViewById(R.id.rent_title);
		TextView shoppingText = (TextView) header.findViewById(R.id.shopping_title);
		TextView otherText = (TextView) header.findViewById(R.id.other_title);
		
		TextView foodCost = (TextView) header.findViewById(R.id.food_cost);
		TextView billsCost = (TextView) header.findViewById(R.id.bills_cost);
		TextView leisureCost = (TextView) header.findViewById(R.id.leisure_cost);
		TextView travelCost = (TextView) header.findViewById(R.id.travel_cost);
		
		TextView utilitiesCost = (TextView) header.findViewById(R.id.utilities_cost);
		TextView rentCost = (TextView) header.findViewById(R.id.rent_cost);
		TextView shoppingCost = (TextView) header.findViewById(R.id.shopping_cost);
		
		TextView otherCost = (TextView) header.findViewById(R.id.other_cost);
		
		BigDecimal total = BigDecimal.ZERO;
		BigDecimal food = BigDecimal.ZERO;
		BigDecimal bills = BigDecimal.ZERO;
		BigDecimal leisure = BigDecimal.ZERO;
		BigDecimal travel = BigDecimal.ZERO;
		BigDecimal utilities = BigDecimal.ZERO;
		BigDecimal rent = BigDecimal.ZERO;
		BigDecimal shopping = BigDecimal.ZERO;
		BigDecimal other = BigDecimal.ZERO;
		
		for (TransactionData entry: data) {
			if(entry.isExpenseType()){
				total = total.add(new BigDecimal(entry.getCost()));
			}
			if(entry.getExpenseCategory() != null){
				if(entry.getExpenseCategory() == ExpenseCategory.Food){
					food = food.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Bills){
					bills = bills.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Leisure){
					leisure = leisure.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Travel){
					travel = travel.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Utilities){
					utilities = utilities.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Rent){
					rent = rent.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Shopping){
					shopping = shopping.add(new BigDecimal(entry.getCost()));
				}
				if(entry.getExpenseCategory() == ExpenseCategory.Other){
					other = other.add(new BigDecimal(entry.getCost()));
				}
			}
		}
		String totalString = UtilMethods.getCostToString(context, total.floatValue());
		String budgetString = UtilMethods.getCostToString(context, Float.valueOf(budget));
		
		totalText.setText(totalString);
		budgetText.setText(budgetString);

		createSlice(ExpenseCategory.Food, foodText, foodCost, donutGraph, food, R.color.food);
		createSlice(ExpenseCategory.Bills, billsText, billsCost, donutGraph, bills, R.color.bills);
		createSlice(ExpenseCategory.Leisure, leisureText, leisureCost, donutGraph, leisure, R.color.leisure);
		createSlice(ExpenseCategory.Travel, travelText, travelCost, donutGraph, travel, R.color.travel);
		
		createSlice(ExpenseCategory.Utilities, utilitiesText, utilitiesCost, donutGraph, utilities, R.color.utilities);
		createSlice(ExpenseCategory.Rent, rentText, rentCost, donutGraph, rent, R.color.rent);
		createSlice(ExpenseCategory.Shopping, shoppingText, shoppingCost, donutGraph, shopping, R.color.shopping);
		
		createSlice(ExpenseCategory.Other, otherText, otherCost, donutGraph, other, R.color.other);
		
		donutGraph.setTotal(Float.valueOf(budget));
		donutGraph.setThickness(10);
		
	}

	private void createSlice(ExpenseCategory expenseCategory, TextView tvTitle1, TextView tvCost1, DonutGraph tvPie, BigDecimal totalBasics, int colourRef) {
		int colour = getResources().getColor(colourRef);
		DonutSlice slice = new DonutSlice();
		slice.setColor(colour);
		tvTitle1.setTextColor(colour);
		tvCost1.setTextColor(colour);
		tvTitle1.setText(expenseCategory.toString());
		tvCost1.setText(UtilMethods.getCostToString(context, totalBasics.floatValue()));
		slice.setValue(totalBasics.floatValue());
		tvPie.addSlice(slice);
	}
	
	private void drawLineGraph(View header) {
		
		TextView totalText = (TextView) header.findViewById(R.id.totalOutgoings_value);
		TextView startText = (TextView) header.findViewById(R.id.graphStart);
		TextView endText = (TextView) header.findViewById(R.id.graphEnd);
		LineGraph lineGraph = (LineGraph) header.findViewById(R.id.linegraph);
		
		Line l1 = new Line();
		int colour = getResources().getColor(R.color.expense);
		l1.setColor(colour);
		
		Calendar startCalendar = new GregorianCalendar();
		startCalendar.setTime(latest.getTime());
		
		Calendar endCalendar = new GregorianCalendar();
		
		
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(new Date());
		
		Calendar mycal = Calendar.getInstance();
		mycal.setTime(cal1.getTime());
		mycal.add(Calendar.MONTH, -1 * month);
		

		int earliestDiffYear = endCalendar.get(Calendar.YEAR) - mycal.get(Calendar.YEAR);
		int earliestDiffMonth = earliestDiffYear * 12 + endCalendar.get(Calendar.MONTH) - mycal.get(Calendar.MONTH);
		
		int daysInMonth;
		int firstDayInMonth;
		int lastDayInMonth;
		int fullDays = mycal.getActualMaximum(Calendar.DAY_OF_MONTH);
		if(earliestDiffMonth == 0){
			
			lastDayInMonth = mycal.get(Calendar.DAY_OF_MONTH);
			daysInMonth = mycal.get(Calendar.DAY_OF_MONTH);
		}else{
			lastDayInMonth = fullDays;
			daysInMonth = fullDays;
		}
		

		firstDayInMonth = 0;
		
		
		SparseArray<BigDecimal> cumCost = new SparseArray<BigDecimal>(daysInMonth);
		for (TransactionData entry: data) {
			if(entry.isExpenseType()){
				Calendar calendar = new GregorianCalendar();
				calendar.setTime(entry.getTimeDate());
				int day = calendar.get(Calendar.DAY_OF_MONTH);
				BigDecimal prev = cumCost.get(day-1);
				if(prev == null){
					cumCost.append(day-1, new BigDecimal(entry.getCost()));
				}else{
					cumCost.append(day-1,prev.add(new BigDecimal(entry.getCost())));
				}
			}

		}

		BigDecimal start = BigDecimal.ZERO;
		for(int pos = firstDayInMonth; pos < lastDayInMonth +1; pos++){
			LinePoint p = new LinePoint();
			p.setX(pos);
			BigDecimal cost = cumCost.get(pos-1);
			if(cost == null){
				cost = start;
			}else{
				cost = cost.add(start);
			}
			
			p.setY(cost.floatValue());
			start = cost;
			l1.addPoint(p);
		}
			
		if(start.compareTo(BigDecimal.ZERO) == 0){
			lineGraph.setAllZero(true);
		}else{
			lineGraph.setAllZero(false);
		}
			
		totalText.setText(UtilMethods.getCostToString(context, start.floatValue()) );

		lineGraph.addLine(l1);
		lineGraph.setRangeX(0, fullDays+1);
		lineGraph.setLineToFill(0);
		
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, -1 * month);
		
		cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
		startText.setText(UtilMethods.getDayAndMonth(cal));
		
		cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		endText.setText(UtilMethods.getDayAndMonth(cal));	
		
	}

	private void drawBarGraph(View header) {
		
		Calendar startCalendar = new GregorianCalendar();
		startCalendar.setTime(latest.getTime());
		
		Calendar endCalendar = new GregorianCalendar();
		
		Calendar mycal = Calendar.getInstance();
		mycal.add(Calendar.MONTH, -1 * month);
		
	
		int earliestDiffYear = endCalendar.get(Calendar.YEAR) - mycal.get(Calendar.YEAR);
		int earliestDiffMonth = earliestDiffYear * 12 + endCalendar.get(Calendar.MONTH) - mycal.get(Calendar.MONTH);
		
		int daysInMonth;
		int fullDays = mycal.getActualMaximum(Calendar.DAY_OF_MONTH);
		if(earliestDiffMonth == 0){
			
			daysInMonth = mycal.get(Calendar.DAY_OF_MONTH);
		}else{
			daysInMonth = fullDays;
		}
		
		int[] counts = new int[7];
		mycal.set(Calendar.DAY_OF_MONTH, 1);
		for(int i = 1; i <=daysInMonth; i++){
			mycal.set(Calendar.DAY_OF_MONTH,i);
			counts[mycal.get(Calendar.DAY_OF_WEEK)-1]++;
		}
		
		
		
		
		
		
		Calendar cal = Calendar.getInstance();
		float[] vals = new float[7];
		
		float totalValue = 0;
		for(TransactionData entry: data){
			if(entry.isExpenseType()){
				cal.setTime(entry.getTimeDate());
				vals[cal.get(Calendar.DAY_OF_WEEK)-1] += entry.getCost();
				
				totalValue += entry.getCost();
			}

		}
		
		
		ArrayList<Bar> points = new ArrayList<Bar>();
		Bar d1 = new Bar();
		d1.setName("Sun");
		d1.setValue(vals[0] == 0 ? 0: vals[0]/counts[0]);
		Bar d2 = new Bar();
		d2.setName("Mon");
		d2.setValue(vals[1] == 0 ? 0: vals[1]/counts[1]);
		Bar d3 = new Bar();
		d3.setName("Tue");
		d3.setValue(vals[2] == 0 ? 0: vals[2]/counts[2]);
		Bar d4 = new Bar();
		d4.setName("Wed");
		d4.setValue(vals[3] == 0 ? 0: vals[3]/counts[3]);
		Bar d5 = new Bar();
		d5.setName("Thu");
		d5.setValue(vals[4] == 0 ? 0: vals[4]/counts[4]);
		Bar d6 = new Bar();
		d6.setName("Fri");
		d6.setValue(vals[5] == 0 ? 0: vals[5]/counts[5]);
		Bar d7 = new Bar();
		d7.setName("Sat");
		d7.setValue(vals[6] == 0 ? 0: vals[6]/counts[6]);

		points.add(d1);
		points.add(d2);
		points.add(d3);
		points.add(d4);
		points.add(d5);
		points.add(d6);
		points.add(d7);
		float averageValue = totalValue / daysInMonth;
		TextView average = (TextView) header.findViewById(R.id.averageDay_value);
		average.setText(UtilMethods.getCostToString(getActivity(), averageValue));
		
		BarGraph g = (BarGraph)header.findViewById(R.id.bargraph);
		g.setAverageValue(averageValue);
		g.setBars(points);

	}
	
	
	
	
	public int getHeaderCount() {
		return 3;
	}

	public void setCurrentHeaderItem(int i) {
		flipHeaders(i);
	}

	public void setOnPageChangeListener(DotsPageIndicator object) {
		this.headerIndicator = object;
		
	}
	
	public static void setInsets(Activity context, View view) {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
		SystemBarTintManager tintManager = new SystemBarTintManager(context);
		SystemBarTintManager.SystemBarConfig config = tintManager.getConfig();
		view.setPadding(0, config.getPixelInsetTop(true), config.getPixelInsetRight(), config.getPixelInsetBottom());
		}

}
